﻿using System.Collections.Generic;
using System.Linq;

namespace TimetableCSP.Scheduler.Entities
{
	/// <summary>
	/// Represents a class (as in a class that is taught at a school).
	/// </summary>
	public class ClassVariable : AbstractVariable
	{
		public const string ClassroomAttributeName = "ClassRoom";
		public const string TimeslotAttributeName = "TimeSlot";
		
		private string teacher;
		private string name;
		private string courseId = string.Empty;
		private int numberOfStudents;
		private HashSet<string> groups = new HashSet<string>();

		/// <summary>
		/// Gets or sets the number of students in this class.
		/// </summary>
		/// <value>
		/// The number of students.
		/// </value>
		public int NumberOfStudents
		{
			get { return numberOfStudents; }
			set { numberOfStudents = value; }
		}

		/// <summary>
		/// Gets or sets the groups that this class belongs to.
		/// </summary>
		/// <value>
		/// The groups.
		/// </value>
		public HashSet<string> Groups
		{
			get { return groups; }
			set { groups = value; }
		}

		/// <summary>
		/// Gets or sets the name of the class.
		/// </summary>
		/// <value>
		/// The name.
		/// </value>
		public string Name
		{
			get { return name; }
			set { name = value; }
		}

		/// <summary>
		/// Gets or sets the id of the course that this class belongs to.
		/// </summary>
		/// <value>
		/// The course id.
		/// </value>
		public string CourseId
		{
			get { return courseId; }
			set { courseId = value; }
		}

		/// <summary>
		/// Gets or sets the name of the teacher that teaches this class.
		/// </summary>
		/// <value>
		/// The teacher.
		/// </value>
		public string Teacher
		{
			get { return teacher; }
			set { teacher = value; }
		}

		/// <summary>
		/// Gets the timeslot that this class has been placed in.
		/// </summary>
		public int Timeslot
		{
			get
			{
				return this[TimeslotAttributeName];
			}
		}

		/// <summary>
		/// Gets the classroom that this class has been placed in.
		/// </summary>
		public int Classroom
		{
			get
			{
				return this[ClassroomAttributeName];
			}
		}

		/// <summary>
		/// A variable can have one or more attributes (dimensions). This method returns a list of their names.
		/// </summary>
		/// <returns>
		/// A list of attribute names.
		/// </returns>
		public override IEnumerable<string> GetAttributeNames()
		{
			return new string[] { TimeslotAttributeName, ClassroomAttributeName};
		}

		/// <summary>
		/// Constructs and initializes the variable's attributes.
		/// </summary>
		protected override void CreateAttributes()
		{
			this[ClassroomAttributeName] = -1;
			this[TimeslotAttributeName] = -1;
		}

		/// <summary>
		/// Creates a new object that is a copy of the current instance.
		/// </summary>
		/// <returns>
		/// A new object that is a copy of this instance.
		/// </returns>
		public override object Clone()
		{
			ClassVariable clone = new ClassVariable();
			clone.Id = this.Id;
			clone.Teacher = this.Teacher;
			clone.Name = this.Name;
			clone.CourseId = this.CourseId;
			clone.NumberOfStudents = this.NumberOfStudents;
			clone.Groups.UnionWith(this.Groups);
			clone.Pinned = this.Pinned;
			foreach (string attributeName in GetAttributeNames())
			{
				clone[attributeName] = this[attributeName];
				clone.SetDomainCeiling(attributeName, this.GetDomainCeiling(attributeName));
			}
			return clone;
		}

		/// <summary>
		/// Returns a <see cref="System.String"/> that represents this instance.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String"/> that represents this instance.
		/// </returns>
		public override string ToString()
		{
			return string.Format(
				"{0} - {1}. Teacher: {2}. Timeslot: {3}. Classroom: {4}.  Number of students: {5}.  Groups: {6}.  Pinned: {7}.", 
				this.CourseId, 
				this.Name, 
				this.Teacher, 
				this.Timeslot, 
				this.Classroom, 
				this.NumberOfStudents, 
				string.Join(",", this.Groups.ToArray()), 
				this.Pinned );
		}
	}
}
